package fun.codedesign.yinxue.code.php2java.service.visitor;

import fun.codedesign.yinxue.code.engine.antlr.php.PhpParser;
import fun.codedesign.yinxue.code.engine.antlr.php.PhpParserBaseVisitor;
import fun.codedesign.yinxue.code.php2java.model.Php2JavaContext;
import fun.codedesign.yinxue.code.php2java.model.Status;
import fun.codedesign.yinxue.util.StringUtils;
import org.antlr.v4.runtime.TokenStreamRewriter;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.RuleNode;
import org.antlr.v4.runtime.tree.TerminalNode;

public class Php2JavaStringBuilderVisitor extends PhpParserBaseVisitor {

    protected final Php2JavaContext context = new Php2JavaContext();
    protected final TokenStreamRewriter writer;

    public Php2JavaStringBuilderVisitor(TokenStreamRewriter rewriter) {
        this.writer = rewriter;
        context.writer = writer;
    }

    @Override
    public Object visit(ParseTree tree) {
        context.phpBlockContext = tree;
        return super.visit(tree);
    }

    @Override
    public Object visitQualifiedNamespaceName(PhpParser.QualifiedNamespaceNameContext ctx) {
        String phpNamespace = ctx.getText();
        if (phpNamespace.contains("namespace")) {
            String delNamespace = phpNamespace.replace("namespace", "");
            String javaRet = context.mapNamespace(delNamespace);
            println("package " + javaRet + ";", "");
        } else {
            // 非 namespace的过滤
        }
        return super.visitQualifiedNamespaceName(ctx);
    }

    // use common\library\CurlTrait;
    @Override
    public Object visitUseDeclaration(PhpParser.UseDeclarationContext ctx) {
        // 获取use 后的路径，转换为package
        String originPath = ctx.getChild(1).getText();
        String targetImportLine = context.mapUse(originPath);
        println("import " + targetImportLine + ";", "");
        return super.visitUseDeclaration(ctx);
    }

    // class manager { }
    @Override
    public Object visitClassDeclaration(PhpParser.ClassDeclarationContext ctx) {
        //  manager -> Manager
        String originTypeName = ctx.identifier().getText();
        String newTypeName = context.mapClassName(originTypeName);
        println("public class " + newTypeName + " {", "");
        Object ret = visitChildren(ctx);
        print("\n}", " ----exitClassDeclaration");
        return ret;
    }

    // 方法 构造器 实例变量等
    @Override
    public Object visitClassStatement(PhpParser.ClassStatementContext ctx) {
        Object ret = defaultResult();
        PhpParser.IdentifierContext identifier = ctx.identifier();
        if (identifier == null) {
            // 过滤掉实例变量
//            println(ctx.getText(), "  ----enterClassStatement");
            context.switchStatus(Status.CLASS_VARIABLE_START);
            ret = visitChildren(ctx);
            context.switchStatus(Status.CLASS_VARIABALE_END);
            return ret;
        }

        String methodName = identifier.getText();
        // 1. 构建一个方法变量声明节点
        if (methodName.equals("__construct")) {
            context.switchStatus(Status.CLASS_CONSTRUCTOR_START);
            print("public " + context.javaDesc.simpleName, "");
            context.mapConstruct();
            ret = visitChildren(ctx);
            context.switchStatus(Status.CLASS_CONSTRUCTOR_END);
        } else {
            context.switchStatus(Status.CLASS_METHOD_START);
            // {} 由下方 MethodBody来闭合 () 由 enterArguments来 闭合  TODO public void需要配合return
            print("public void " + methodName, "");
            ret = visitChildren(ctx);
            context.switchStatus(Status.CLASS_METHOD_END);
        }
        return ret;
    }

    @Override
    public Object visitVariableInitializer(PhpParser.VariableInitializerContext ctx) {
        Object ret = defaultResult();
        // class变量初始状态时
        if (context.isClassVariableStatus()) {
            String varName = ctx.VarName().getText();
            String newVarName = context.wordChain.invokeRules(varName);
            String initStatement = null;
            if (ctx.constantInitializer() != null) {
                String originInitStatment = ctx.constantInitializer().getText();
                // 需要做语句的转换
                initStatement = context.statementChain.invokeRules(originInitStatment);
            }
            println("Object " + newVarName + "=" + initStatement + ";", "");
        } else if (context.isClassConstrutorStatus()) {

        }
        ret = visitChildren(ctx);

        return ret;
    }

    // TODO 入参，需要配合上面的 ClassStatement来使用
    @Override
    public Object visitFormalParameterList(PhpParser.FormalParameterListContext ctx) {
        Object ret = defaultResult();
        if (context.isClassConstrutorStatus()) {
            print("(", "visitFormalParameterList start");
            ret = visitChildren(ctx);
            String params = StringUtils.joinWithComma(context.cache);
            print(params + ")", "visitFormalParameterList end");
            context.cache.clear();
        } else if (context.isClassMethodStatus()) {
            print("(", "visitFormalParameterList start");
            ret = visitChildren(ctx);
            String params = StringUtils.joinWithComma(context.cache);
            print(params + ")", "visitFormalParameterList end");
            context.cache.clear();
        }
        return ret;
        //print("(" + ctx.getText() + ")", "  ----enterFormalParameterList");
    }

    @Override
    public Object visitAssignmentExpression(PhpParser.AssignmentExpressionContext ctx) {
        return super.visitAssignmentExpression(ctx);
    }

    @Override
    public Object visitFormalParameter(PhpParser.FormalParameterContext ctx) {
        Object ret = defaultResult();
        if (context.isClassConstrutorStatus()) {
            String originText = ctx.getText();
            String targetText = context.wordChain.invokeRules(originText);
            context.cache.add("Object " + targetText);
            ret = visitChildren(ctx);
            return ret;
        } else if (context.isClassMethodStatus()) {
            String originText = ctx.getText();
            String targetText = context.wordChain.invokeRules(originText);
            // 默认使用Object类型作为入参类型
            context.cache.add("Object " + targetText);
            ret = visitChildren(ctx);
            return ret;
        }
        return ret;
    }

    // methodbody方法体
    @Override
    public Object visitMethodBody(PhpParser.MethodBodyContext ctx) {
        print(" {\n", "");
        Object ret = visitChildren(ctx);
//        print("}\n", "");
        return ret;
    }


    @Override
    public Object visitInnerStatement(PhpParser.InnerStatementContext ctx) {
        justPrint(ctx.getText() + "visitInnerStatement start");
        context.switchStatus(Status.MEHOD_LINE_START);
//        context.stack.push(new ArrayList());
        Object ret = visitChildren(ctx);
//        List list = context.stack.pop();
//        context.methodBodyList.add(list);
//        System.out.println(ret + "visitInnerStatement end");

//        System.out.println(list.toString() + "看下面2行对不对");
//        System.out.println(ctx.getText());
//        for (Object o : list) {
//            print(o, "visitInnerStatement end");
//        }
//        System.out.println("\n");
        context.switchStatus(Status.MEHOD_LINE_END);
        return ret;
    }


    // 控制整个child的迭代
    @Override
    public Object visitChildren(RuleNode node) {
        justPrint(node.getText() + "visitChildren RuleNode");
        Object result = defaultResult();
        int n = node.getChildCount();
        for (int i = 0; i < n; i++) {
            if (!shouldVisitNextChild(node, result)) {
                break;
            }

            ParseTree c = node.getChild(i);
            Object childResult = c.accept(this);

            result = aggregateResult(result, childResult);
        }
        return result;
    }

    @Override
    public Object visitTerminal(TerminalNode node) {
        String text = node.getText();
        // 获取method调用容器
        if (context.isMethodLineStatus()) {
//            List<String> methodList = context.stack.peek();
            String changeText = context.wordChain.invokeRules(text);
//            methodList.add(changeText);
            print(changeText, "----methodLine Token");
        }
        return null;
    }

    private void println(Object s, String note) {
//        System.out.println(s + note);
//        context.builder.append(s + "\n");
    }

    private void justPrint(String text) {
//        System.out.println(text);
    }

    private void print(Object s, String note) {
//        System.out.print(s + note);
//        context.builder.append(s);
    }


    public StringBuilder getBuilder() {
        return context.builder;
    }

    public Php2JavaContext getContext() {
        return context;
    }
}
